/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./vVertexBufferManager.h"

namespace Vendetta {
	vVertexBuffer* vVertexBufferManager::CreateVertexBuffer(const vArray<vPoint3D>& vertices,
		const vArray<vPoint2D>& texCoords, const vArray<vPoint3D>& normals,
		const vArray<vColor>& colors, vUInt32 ui32Format, 
		vVertexBuffer::eVertexBufferPrimitiveType ePrimitiveType,
		vVertexBufferManager::eVertexBufferType eType,
		vVertexBuffer::eVertexBufferUsage eUsage) {

		if (!checkIfValid(vertices, texCoords, normals, colors, ui32Format, ePrimitiveType)) {
			return vNull;
		}
		vVertexBuffer* newBuff = apiNewVertexBuffer(vertices.Size(), ui32Format, ePrimitiveType, eType, eUsage);
		if (!newBuff) {
			return vNull;
		}
		newBuff->SetVertices(vertices);
		if (ui32Format & vVertexBuffer::VVBF_NXNYNZ) {
			if (normals.Size() == vertices.Size()) {
				newBuff->SetNormals(normals);
			} else if (normals.Size() == 1) {
				for (vUInt uiInd = 0; uiInd < vertices.Size(); uiInd++) {
					newBuff->SetNormal(uiInd, normals[0]);
				}
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (ui32Format & vVertexBuffer::VVBF_UV) {
			if (texCoords.Size() == vertices.Size()) {
				newBuff->SetTexCoords(texCoords);
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (ui32Format & vVertexBuffer::VVBF_RGBA) {
			if (colors.Size() == vertices.Size()) {
				newBuff->SetColors(colors);
			} else if (colors.Size() == 1) {
				for (vUInt uiInd = 0; uiInd < vertices.Size(); uiInd++) {
					newBuff->SetColor(uiInd, colors[0]);
				}
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (newBuff->build()) {
			newBuff->Lock();
			mBuffers.AddAsLast(newBuff);

			return newBuff;
		} else {
			vDelete(newBuff);

			return vNull;
		}
	}
			
	vVertexBuffer* vVertexBufferManager::CreateVertexBuffer(const vPoint3D* pVertices,
		const vPoint2D* pTexCoords, const vPoint3D* pNormals,
		const vColor* pColors, vUInt uiVertexCount, vUInt uiTexCoordCount, 
		vUInt uiNormalCount, vUInt uiColorCount, vUInt32 ui32Format, 
		vVertexBuffer::eVertexBufferPrimitiveType ePrimitiveType,
		vVertexBufferManager::eVertexBufferType eType,
		vVertexBuffer::eVertexBufferUsage eUsage) {
		
		if (!checkIfValid(pVertices, pTexCoords, pNormals, pColors,
						uiVertexCount, uiTexCoordCount, uiNormalCount,
						uiColorCount, ui32Format, ePrimitiveType)) {
			return vNull;
		}
		vVertexBuffer* newBuff = apiNewVertexBuffer(uiVertexCount, ui32Format, ePrimitiveType, eType, eUsage);
		if (!newBuff) {
			return vNull;
		}
		newBuff->SetVertices(pVertices, uiVertexCount);
		if (ui32Format & vVertexBuffer::VVBF_NXNYNZ) {
			if (uiNormalCount == uiVertexCount) {
				newBuff->SetNormals(pNormals, uiNormalCount);
			} else if (uiNormalCount == 1) {
				for (vUInt uiInd = 0; uiInd < uiVertexCount; uiInd++) {
					newBuff->SetNormal(uiInd, pNormals[0]);
				}
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (ui32Format & vVertexBuffer::VVBF_UV) {
			if (uiTexCoordCount == uiVertexCount) {
				newBuff->SetTexCoords(pTexCoords, uiTexCoordCount);
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (ui32Format & vVertexBuffer::VVBF_RGBA) {
			if (uiColorCount == uiVertexCount) {
				newBuff->SetColors(pColors, uiColorCount);
			} else if (uiColorCount == 1) {
				for (vUInt uiInd = 0; uiInd < uiVertexCount; uiInd++) {
					newBuff->SetColor(uiInd, pColors[0]);
				}
			} else {
				vDelete(newBuff);
				return vNull;
			}
		}
		if (newBuff->build()) {
			newBuff->Lock();
			mBuffers.AddAsLast(newBuff);
			
			return newBuff;
		} else {
			vDelete(newBuff);

			return vNull;
		}
	}
				
	vBool vVertexBufferManager::DeleteVertexBuffer(vVertexBuffer* pBuffer) {
		if (pBuffer) {
			if (mBuffers.Contains(pBuffer)) {
				vUInt uiIndex = mBuffers.Find(pBuffer);
				mBuffers[uiIndex]->Unlock();
				vDelete(mBuffers[uiIndex]);
				mBuffers.Remove(uiIndex);
				
				return true;
			}
		}
		return false;
	}

	vVertexBufferManager::vVertexBufferManager() {
	}
	
	vVertexBufferManager::~vVertexBufferManager() {
		for (vUInt uiIndex = 0; uiIndex < mBuffers.Size(); uiIndex++) {
			vDelete(mBuffers[uiIndex]);
		}
		mBuffers.Clear();
	}
	
	vBool vVertexBufferManager::checkIfValid(const vArray<vPoint3D>& vertices,
		const vArray<vPoint2D>& texCoords, const vArray<vPoint3D>& normals,
		const vArray<vColor>& colors, vUInt32 ui32Format, 
		vVertexBuffer::eVertexBufferPrimitiveType ePrimitiveType) {
		
		if (vertices.IsEmpty()) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_NXNYNZ && normals.IsEmpty()) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_UV && texCoords.IsEmpty()) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_RGBA && colors.IsEmpty()) {
			return false;
		}
		
		return true;
	}
		
	vBool vVertexBufferManager::checkIfValid(const vPoint3D* pVertices,
		const vPoint2D* pTexCoords, const vPoint3D* pNormals,
		const vColor* pColors, vUInt uiVertexCount, vUInt uiTexCoordCount, 
		vUInt uiNormalCount, vUInt uiColorCount, vUInt32 ui32Format, 
		vVertexBuffer::eVertexBufferPrimitiveType ePrimitiveType) {
		
		if (!pVertices || !uiVertexCount) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_NXNYNZ && (!pNormals || !uiNormalCount)) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_UV && (!pTexCoords || !uiTexCoordCount)) {
			return false;
		}
		if (ui32Format & vVertexBuffer::VVBF_RGBA && (!pColors || !uiColorCount)) {
			return false;
		}
		
		return true;
	}
	
	/************************************************************************/
	/* Disabled                                                             */
	/************************************************************************/
	vVertexBufferManager::vVertexBufferManager(const vVertexBufferManager& buffer) {
		V_CHECK_MSG(0, "Some tries to call vVertexBufferManager copy ctor."); 
	}
	
	vVertexBufferManager& vVertexBufferManager::operator=(const vVertexBufferManager& buffer) {
		V_CHECK_MSG(0, "Some tries to call vVertexBufferManager operator=."); 

		return *this;
	}
	/************************************************************************/
}